热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

表面|发生_ffmpeg调用directshowcamera并sdl渲染

篇首语:本文由编程笔记#小编为大家整理,主要介绍了ffmpeg调用directshowcamera并sdl渲染相关的知识,希望对你有一定的参考价值。基础

篇首语:本文由编程笔记#小编为大家整理,主要介绍了ffmpeg调用directshow camera 并sdl渲染相关的知识,希望对你有一定的参考价值。



基础

ffmpeg使用设备先注册

avdevice_register_all();

使用常用得CCameraDS 取获取名称,这里使用第一个摄像头。这里我们使用SDL来渲染得时候,启动一个定时器来定时给一个事件让SDL来刷新

SDLSDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);

所以使用video和timer来完成这种渲染。


渲染流程

这里使用bgr24来渲染,使用sdl 创建表面,指定opengl来做
1 创建窗口
2 创建刷新线程
3 线程中发送更新事件
4 main主循环捕获事件,获取一帧rgb24,刷新界面渲染

这里面可以修改变成这样
刷新线程渲染获取一帧,推给主线程,主线程负责编码发送,同时渲染,这里是示例,没有这么做。

int main()

avdevice_register_all();
int w = 1280;
int h = 720;
g_fps = 10;
std::wstring cname;
CCameraDS::CameraName(0, cname);
std::string name = UnicodeToUTF8(cname);
TFFCap cap;

int ret = cap.OpenCameraRGB(name.c_str(), 1280, 720);
if (ret != 0)
return -1;
int screen_w, screen_h;
SDL_Window *screen;
SDL_Renderer *sdlRenderer;
SDL_Texture *sdlTexture;
SDL_Rect sdlRect;
SDL_Thread *video_tid;
SDL_Event event;

SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
screen_w = w; //w;
screen_h = h;
//screen_h = screen_w * 9 / 16;
screen = SDL_CreateWindow("FF", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
screen_w, screen_h, SDL_WINDOW_OPENGL);
if (!screen)

std::cout << "SDL: could not create window - exiting: " << SDL_GetError() << std::endl;
return -1;

sdlRenderer &#61; SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED);
sdlTexture &#61; SDL_CreateTexture(sdlRenderer,
SDL_PIXELFORMAT_BGR24 , //SDL_PIXELFORMAT_IYUV, //SDL_PIXELFORMAT_BGR24
SDL_TEXTUREACCESS_STREAMING,/*SDL_TEXTUREACCESS_STREAMING,*/

screen_w, screen_h);
sdlRect.x &#61; 0;
sdlRect.y &#61; 0;
sdlRect.w &#61; screen_w;
sdlRect.h &#61; screen_h;
video_tid &#61; SDL_CreateThread(sfp_refresh_thread, NULL, NULL);
int got_picture;
for (;;)

SDL_WaitEvent(&event);
if (event.type &#61;&#61; SFM_REFRESH_EVENT)

uint8_t *frame &#61; cap.QueryFrame();
if (frame !&#61; NULL)

int y &#61; screen_h * 2 / 3;
SDL_UpdateTexture(sdlTexture, NULL/*&sdlRect*/, frame, w * 3);
//SDL_UpdateTexture(sdlTexture, &sdlRect, out_buffer &#43; W * H * 3, -W * 3);
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
SDL_RenderPresent(sdlRenderer);


else if (event.type &#61;&#61; SDL_KEYDOWN)

if (event.key.keysym.sym &#61;&#61; SDLK_SPACE)
thread_pause &#61; !thread_pause;

else if (event.type &#61;&#61; SDL_QUIT)

thread_exit &#61; 1;

else if (event.type &#61;&#61; SFM_BREAK_EVENT)

break;



SDL使用得事件如下&#xff1a;

int thread_exit &#61; 0;
int thread_pause &#61; 0;
int g_fps &#61; 30;
int sfp_refresh_thread(void *opaque)

thread_exit &#61; 0;
thread_pause &#61; 0;
while (!thread_exit)

if (!thread_pause)

SDL_Event event;
event.type &#61; SFM_REFRESH_EVENT;
SDL_PushEvent(&event);

SDL_Delay(1000/g_fps);

thread_exit &#61; 0;
thread_pause &#61; 0;
//Break
SDL_Event event;
event.type &#61; SFM_BREAK_EVENT;
SDL_PushEvent(&event);
return 0;

线程里面每隔1000/g_fps得时间就产生一个渲染事件&#xff0c;取得一帧数据后渲染&#xff0c;当然这里也可以编码发送等等都可以做。事件发生等等也可以使用标准c&#43;&#43;得事件等待互斥&#xff0c;原理都是一摸一样得。

最后给出实现得FFcap


TFFCap声明

class TFFCap

public:
int m_fps &#61; 10;
AVFrame * m_pFrame &#61; NULL;
AVFrame * m_pFrameDst &#61; NULL;
string m_name;
uint8_t * out_buffer &#61; NULL;
int m_videoIndex &#61; -1;
struct SwsContext * m_img_convert_ctx &#61; NULL;
//int _pixelW;
//int _pixelH;
private:
AVFormatContext * m_pFormatCtx &#61; NULL;
AVCodecContext * m_pCodecCtx &#61; NULL;
AVCodec * m_pCodec &#61; NULL;
AVPacket * m_pkt &#61; NULL;
public:
void Init()

avdevice_register_all();

int OpenCameraRGB(const char * utf8videoname,
int nWidth, int nHeight);
uint8_t *QueryFrame();
int m_w &#61; 0;
int m_h &#61; 0;
// int QueryFrame(uint8_t *buf, int *len);
void UnInit();
TFFCap();
~TFFCap();
;

TFFCap实现

#include "FFCap.h"
#include
#include
using namespace std;
TFFCap::TFFCap()


TFFCap::~TFFCap()


static AVDictionary *GetOptions(int videosize, int &fps)

AVDictionary *options &#61; NULL;
switch (videosize)

case 1:

fps &#61; 10;
av_dict_set(&options, "video_size", "1280x720", 0);
//const char * fname &#61; av_get_pix_fmt_name((AVPixelFormat)13);
//av_dict_set(&options, "pixel_format", fname, 0);
av_dict_set_int(&options, "framerate", 10, 0);
av_dict_set_int(&options, "rtbufsize", 2764800 / 10, 0);
av_dict_set(&options, "start_time_realtime", 0, 0);
//av_dict_set(&options, "mjpeg", 0, 0);

break;
case 2:
fps &#61; 20;
av_dict_set_int(&options, "framerate", 30, 0);
av_dict_set(&options, "video_size", "640x480", 0);
av_dict_set_int(&options, "rtbufsize", 640 * 480 * 3 / 15, 0);
break;
case 3:
fps &#61; 20;
av_dict_set_int(&options, "framerate", 30, 0);
av_dict_set(&options, "video_size", "320x240", 0);
av_dict_set_int(&options, "rtbufsize", 76800 / 10, 0);
break;
case 4:
fps &#61; 20;
av_dict_set_int(&options, "framerate", 30, 0);
av_dict_set(&options, "video_size", "176x144", 0);
//av_dict_set_int(&options, "rtbufsize", 76800 / 10, 0);
break;

av_dict_set(&options, "start_time_realtime", 0, 0);
return options;

int TFFCap::OpenCameraRGB(const char * utf8videoname,
int w, int h)

av_log_set_level(AV_LOG_FATAL);
AVInputFormat *ifmt &#61; nullptr;
AVDictionary *options &#61; NULL;
string oldname &#61; m_name;
m_name &#61; "video&#61;";
m_name &#43;&#61; utf8videoname;
if (oldname.compare(m_name) !&#61; 0)

avcodec_close(m_pCodecCtx);
avcodec_free_context(&m_pCodecCtx);
m_pCodecCtx &#61; NULL;
avformat_close_input(&m_pFormatCtx);
m_pFormatCtx &#61; NULL;

else

if (m_w &#61;&#61; w && m_h &#61;&#61; h)
return 0;
avcodec_free_context(&m_pCodecCtx);
m_pCodecCtx &#61; NULL;
avformat_close_input(&m_pFormatCtx);
m_pFormatCtx &#61; NULL;

if (m_pFormatCtx &#61;&#61; NULL)

m_pFormatCtx &#61; avformat_alloc_context();
ifmt &#61; av_find_input_format("dshow");

m_pFormatCtx->flags |&#61; AVFMT_FLAG_NOBUFFER;
av_dict_set(&options, "start_time_realtime", 0, 0);
switch (w)

case 1920:
break;
case 1280:
m_fps &#61; 10;
av_dict_set(&options, "video_size", "1280x720", 0);
//av_dict_set_int(&options, "framerate", 10, 0);
av_dict_set_int(&options, "rtbufsize", 2764800 / 10, 0);
break;
case 640:
m_fps &#61; 20;
av_dict_set_int(&options, "framerate", 30, 0);
av_dict_set(&options, "video_size", "640x480", 0);
av_dict_set_int(&options, "rtbufsize", 640 * 480 * 3 / 15, 0);
break;
case 320:
m_fps &#61; 20;
av_dict_set_int(&options, "framerate", 30, 0);
av_dict_set(&options, "video_size", "320x240", 0);
av_dict_set_int(&options, "rtbufsize", 76800 / 10, 0);
break;
case 176:
m_fps &#61; 20;
av_dict_set_int(&options, "framerate", 30, 0);
av_dict_set(&options, "video_size", "176x144", 0);
av_dict_set_int(&options, "rtbufsize", 76800 / 10, 0);
break;

if (avformat_open_input(&m_pFormatCtx, m_name.c_str(), ifmt, &options) !&#61; 0)

return -1;

if (avformat_find_stream_info(m_pFormatCtx, NULL) < 0)

//std::cout <<"avformat find stream info failed." <
return -1;

for (uint32_t i &#61; 0; i < m_pFormatCtx->nb_streams; i&#43;&#43;)

if (m_pFormatCtx->streams[i]->codecpar->codec_type &#61;&#61; AVMEDIA_TYPE_VIDEO)

//AVPixelFormat avf &#61; (AVPixelFormat)m_pFormatCtx->streams[i]->codecpar->format;
//const char* strfmt &#61; av_get_pix_fmt_name(avf);
//w &#61; m_pFormatCtx->streams[i]->codecpar->width;
//h &#61; m_pFormatCtx->streams[i]->codecpar->height;
m_videoIndex &#61; i;
break;


if (-1 &#61;&#61; m_videoIndex)

return -1;

if(m_pCodecCtx &#61;&#61; NULL)
m_pCodecCtx &#61; avcodec_alloc_context3(NULL);
if (m_pCodecCtx &#61;&#61; NULL)

return -1;

avcodec_parameters_to_context(m_pCodecCtx, m_pFormatCtx->streams[m_videoIndex]->codecpar);
m_pCodec &#61; avcodec_find_decoder(m_pCodecCtx->codec_id);
if (m_pCodec &#61;&#61; NULL)

//std::cout <<"AVCodec not found." <
return -1;

if (avcodec_open2(m_pCodecCtx, m_pCodec, NULL) < 0)

//std::cout <<"codec open failed." <
return -1;

if(m_pFrame &#61;&#61; NULL)
m_pFrame &#61; av_frame_alloc();
if(m_pFrameDst &#61;&#61; NULL)
m_pFrameDst &#61; av_frame_alloc();
if(m_pkt &#61;&#61; NULL)
m_pkt &#61; av_packet_alloc();
AVPixelFormat avpf &#61; AV_PIX_FMT_BGR24; // AV_PIX_FMT_YUV420P; //AV_PIX_FMT_BGR24
if (m_w !&#61; w || m_h !&#61; h)

if (out_buffer !&#61; NULL)
delete []out_buffer;

if (out_buffer &#61;&#61; NULL)

out_buffer &#61; (unsigned char *)av_malloc(av_image_get_buffer_size(avpf,
w,
h,
1));
av_image_fill_arrays(m_pFrameDst->data, m_pFrameDst->linesize, out_buffer,
avpf, w, h, 1);

m_img_convert_ctx &#61;
sws_getCachedContext(m_img_convert_ctx,
w, h, m_pCodecCtx->pix_fmt,
w, h, avpf, SWS_POINT, NULL, NULL, NULL);

m_w &#61; w;
m_h &#61; h;
return 0;

uint8_t *TFFCap::QueryFrame(/*int &len*/)

if (m_pFormatCtx &#61;&#61; NULL)
return NULL;
AVPacket packet;
av_init_packet(&packet);
int got_picture &#61; 0;
if (av_read_frame(m_pFormatCtx, &packet) >&#61; 0)

int ret &#61; 0;
if (packet.stream_index &#61;&#61; m_videoIndex)

if (avcodec_send_packet(m_pCodecCtx, &packet) &#61;&#61; 0)
if (avcodec_receive_frame(m_pCodecCtx, m_pFrame) &#61;&#61; 0)

got_picture &#61; 1;
sws_scale(m_img_convert_ctx,
(const uint8_t* const*)m_pFrame->data,
m_pFrame->linesize, 0,
m_pCodecCtx->height,
m_pFrameDst->data, m_pFrameDst->linesize);

av_packet_unref(&packet);



//返回上一帧
if (got_picture)
return out_buffer;
return NULL;

void TFFCap::UnInit()

av_frame_free(&m_pFrameDst);
av_frame_free(&m_pFrame);
if(m_img_convert_ctx!&#61; nullptr)
sws_freeContext(m_img_convert_ctx);
avcodec_close(m_pCodecCtx);
avcodec_free_context(&m_pCodecCtx);
avformat_close_input(&m_pFormatCtx);


效果


代码里面还有一些是可以修改得&#xff0c;仅仅作为示例&#xff0c;代表可行


推荐阅读
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • Python爬虫中使用正则表达式的方法和注意事项
    本文介绍了在Python爬虫中使用正则表达式的方法和注意事项。首先解释了爬虫的四个主要步骤,并强调了正则表达式在数据处理中的重要性。然后详细介绍了正则表达式的概念和用法,包括检索、替换和过滤文本的功能。同时提到了re模块是Python内置的用于处理正则表达式的模块,并给出了使用正则表达式时需要注意的特殊字符转义和原始字符串的用法。通过本文的学习,读者可以掌握在Python爬虫中使用正则表达式的技巧和方法。 ... [详细]
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • ***byte(字节)根据长度转成kb(千字节)和mb(兆字节)**parambytes*return*publicstaticStringbytes2kb(longbytes){ ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了在MFC下利用C++和MFC的特性动态创建窗口的方法,包括继承现有的MFC类并加以改造、插入工具栏和状态栏对象的声明等。同时还提到了窗口销毁的处理方法。本文详细介绍了实现方法并给出了相关注意事项。 ... [详细]
  • 本文介绍了在使用Laravel和sqlsrv连接到SQL Server 2016时,如何在插入查询中使用输出子句,并返回所需的值。同时讨论了使用CreatedOn字段返回最近创建的行的解决方法以及使用Eloquent模型创建后,值正确插入数据库但没有返回uniqueidentifier字段的问题。最后给出了一个示例代码。 ... [详细]
author-avatar
通天论坛it技术
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有